<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>回调函数工作原理演示</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
    <script>
        tailwind.config = {
            theme: {
                extend: {
                    colors: {
                        primary: '#3b82f6',
                        secondary: '#10b981',
                        accent: '#f59e0b',
                        dark: '#1e293b',
                    },
                    fontFamily: {
                        sans: ['Inter', 'system-ui', 'sans-serif'],
                    },
                }
            }
        }
    </script>
    <style type="text/tailwindcss">
        @layer utilities {
            .step-active {
                @apply bg-primary text-white border-primary;
            }
            .step-pending {
                @apply bg-gray-100 text-gray-400 border-gray-200;
            }
            .step-completed {
                @apply bg-secondary text-white border-secondary;
            }
            .flow-line {
                @apply h-1 flex-1 my-auto mx-2;
            }
        }
    </style>
</head>
<body class="bg-gray-50 min-h-screen p-4 md:p-8">
    <div class="max-w-5xl mx-auto bg-white rounded-lg rounded-xl-8 rounded-xl shadow-lg">
        <div class="p-6 md:p-8">
            <h1 class="text-2xl md:text-3xl font-bold text-dark mb-6">
                <i class="fa fa-code-fork text-primary mr-2"></i>回调函数（callback）工作原理演示
            </h1>
            
            <div class="mb-8 bg-blue-50 p-4 rounded-lg border border-blue-100">
                <p class="text-gray-700">
                    回调函数是作为参数传递给另一个函数的函数，当第一个函数完成操作后，会调用这个回调函数。
                    在你提供的代码中，<code class="bg-white px-1 py-0.5 rounded text-primary font-mono">GetStudentByID</code>
                    完成数据库查询后，会调用传入的回调函数并将结果传递给它。
                </p>
            </div>

            <!-- 演示控制区 -->
            <div class="mb-8">
                <div class="flex flex-col md:flex-row gap-4 items-start md:items-center">
                    <div class="flex-1">
                        <label for="studentId" class="block text-sm font-medium text-gray-700 mb-1">输入学生ID:</label>
                        <input 
                            type="text" 
                            id="studentId" 
                            value="S1001" 
                            class="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-primary focus:border-primary"
                        >
                    </div>
                    <button 
                        id="startDemo" 
                        class="bg-primary hover:bg-primary/90 text-white px-6 py-2 rounded-md transition duration-200 flex items-center"
                    >
                        <i class="fa fa-play mr-2"></i>开始演示
                    </button>
                    <button 
                        id="resetDemo" 
                        class="bg-gray-200 hover:bg-gray-300 text-gray-700 px-6 py-2 rounded-md transition duration-200 flex items-center"
                    >
                        <i class="fa fa-refresh mr-2"></i>重置
                    </button>
                </div>
            </div>

            <!-- 流程展示 -->
            <div class="mb-8">
                <h2 class="text-xl font-semibold text-gray-700 mb-4">执行流程</h2>
                
                <div class="flex items-center mb-8">
                    <div id="step1" class="step-pending w-10 h-10 rounded-full border-2 flex items-center justify-center font-semibold z-10">1</div>
                    <div class="flow-line bg-gray-200"></div>
                    <div id="step2" class="step-pending w-10 h-10 rounded-full border-2 flex items-center justify-center font-semibold z-10">2</div>
                    <div class="flow-line bg-gray-200"></div>
                    <div id="step3" class="step-pending w-10 h-10 rounded-full border-2 flex items-center justify-center font-semibold z-10">3</div>
                </div>
                
                <div class="grid grid-cols-1 md:grid-cols-3 gap-4 text-center">
                    <div class="bg-gray-50 p-4 rounded-lg border border-gray-200">
                        <p class="font-medium">调用 GetStudentByID 方法</p>
                        <p class="text-sm text-gray-500 mt-1">传入ID和回调函数</p>
                    </div>
                    <div class="bg-gray-50 p-4 rounded-lg border border-gray-200">
                        <p class="font-medium">执行数据库查询</p>
                        <p class="text-sm text-gray-500 mt-1">查找匹配的学生信息</p>
                    </div>
                    <div class="bg-gray-50 p-4 rounded-lg border border-gray-200">
                        <p class="font-medium">调用回调函数</p>
                        <p class="text-sm text-gray-500 mt-1">将查询结果传递给回调</p>
                    </div>
                </div>
            </div>

            <!-- 模拟代码执行展示 -->
            <div class="mb-8">
                <h2 class="text-xl font-semibold text-gray-700 mb-4">执行过程</h2>
                <div id="executionLog" class="bg-gray-900 text-gray-100 p-4 rounded-lg h-64 overflow-y-auto font-mono text-sm">
                    <p class="text-gray-400">等待演示开始...</p>
                </div>
            </div>

            <!-- 可视化展示 -->
            <div class="mb-4">
                <h2 class="text-xl font-semibold text-gray-700 mb-4">数据传递可视化</h2>
                <div class="flex flex-col md:flex-row items-center justify-between">
                    <!-- 调用者 -->
                    <div class="w-full md:w-1/3 bg-gray-50 p-4 rounded-lg border-2 border-gray-200 mb-6 md:mb-0">
                        <h3 class="text-center font-medium mb-3">主程序</h3>
                        <div id="mainProgram" class="text-center">
                            <p>准备调用 GetStudentByID</p>
                            <p class="mt-2 text-sm">参数: ID = <span id="displayId">S1001</span></p>
                            <p class="text-sm">回调函数: 处理查询结果</p>
                        </div>
                    </div>

                    <!-- 箭头 -->
                    <div class="hidden md:block text-4xl text-gray-400">
                        <i class="fa fa-long-arrow-right"></i>
                    </div>
                    <div class="md:hidden text-4xl text-gray-400 my-4">
                        <i class="fa fa-long-arrow-down"></i>
                    </div>

                    <!-- GetStudentByID方法 -->
                    <div class="w-full md:w-1/3 bg-gray-50 p-4 rounded-lg border-2 border-primary mb-6 md:mb-0">
                        <h3 class="text-center font-medium mb-3 text-primary">GetStudentByID</h3>
                        <div id="getStudentMethod" class="text-center">
                            <p>正在执行数据库查询</p>
                            <p class="mt-2 text-sm">查询ID: <span id="methodId">等待输入...</span></p>
                        </div>
                    </div>

                    <!-- 箭头 -->
                    <div class="hidden md:block text-4xl text-gray-400">
                        <i class="fa fa-long-arrow-right"></i>
                    </div>
                    <div class="md:hidden text-4xl text-gray-400 my-4">
                        <i class="fa fa-long-arrow-down"></i>
                    </div>

                    <!-- 回调函数 -->
                    <div class="w-full md:w-1/3 bg-gray-50 p-4 rounded-lg border-2 border-secondary">
                        <h3 class="text-center font-medium mb-3 text-secondary">回调函数</h3>
                        <div id="callbackFunction" class="text-center">
                            <p>等待接收查询结果</p>
                            <p id="callbackResult" class="mt-2 text-sm text-gray-500">结果将显示在这里</p>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>

    <script>
        // 模拟学生数据库
        const studentDatabase = [
            { ID: 'S1001', 姓名: '张三', 班级: '高一(1)班', 年龄: 16 },
            { ID: 'S1002', 姓名: '李四', 班级: '高一(2)班', 年龄: 17 },
            { ID: 'S1003', 姓名: '王五', 班级: '高一(1)班', 年龄: 16 }
        ];

        // 模拟GetStudentByID方法
        function GetStudentByID(id, callback) {
            log(`调用 GetStudentByID 方法，ID: ${id}`);
            log('开始执行数据库查询...');
            
            // 更新步骤2为活动状态
            updateStep(2, 'active');
            
            // 模拟数据库查询延迟
            setTimeout(() => {
                log('数据库查询完成');
                
                // 查找匹配的学生
                const result = studentDatabase.filter(student => student.ID === id);
                
                if (result.length === 0) {
                    log('未找到匹配的学生记录');
                } else {
                    log(`找到 ${result.length} 条匹配记录`);
                }
                
                // 更新步骤2为已完成，步骤3为活动状态
                updateStep(2, 'completed');
                updateStep(3, 'active');
                
                log('准备调用回调函数，将结果传递过去');
                
                // 调用回调函数，将结果传递给它
                setTimeout(() => {
                    callback(result);
                }, 1000);
            }, 2000);
        }

        // 日志输出函数
        function log(message) {
            const logElement = document.getElementById('executionLog');
            const timestamp = new Date().toLocaleTimeString();
            const logEntry = document.createElement('p');
            logEntry.innerHTML = `<span class="text-green-400">[${timestamp}]</span> ${message}`;
            logElement.appendChild(logEntry);
            logElement.scrollTop = logElement.scrollHeight;
        }

        // 更新步骤状态
        function updateStep(stepNumber, state) {
            const stepElement = document.getElementById(`step${stepNumber}`);
            const lineElements = document.querySelectorAll('.flow-line');
            
            // 移除所有状态类
            stepElement.classList.remove('step-active', 'step-pending', 'step-completed');
            
            // 添加当前状态类
            stepElement.classList.add(`step-${state}`);
            
            // 更新连接线
            if (state === 'completed' && stepNumber < 3) {
                lineElements[stepNumber - 1].classList.remove('bg-gray-200');
                lineElements[stepNumber - 1].classList.add('bg-secondary');
            }
        }

        // 重置演示
        function resetDemo() {
            // 重置步骤状态
            updateStep(1, 'pending');
            updateStep(2, 'pending');
            updateStep(3, 'pending');
            
            // 重置连接线
            const lineElements = document.querySelectorAll('.flow-line');
            lineElements.forEach(line => {
                line.classList.remove('bg-secondary');
                line.classList.add('bg-gray-200');
            });
            
            // 重置日志
            document.getElementById('executionLog').innerHTML = '<p class="text-gray-400">等待演示开始...</p>';
            
            // 重置可视化区域
            document.getElementById('mainProgram').innerHTML = `
                <p>准备调用 GetStudentByID</p>
                <p class="mt-2 text-sm">参数: ID = <span id="displayId">${document.getElementById('studentId').value}</span></p>
                <p class="text-sm">回调函数: 处理查询结果</p>
            `;
            
            document.getElementById('getStudentMethod').innerHTML = `
                <p>正在执行数据库查询</p>
                <p class="mt-2 text-sm">查询ID: <span id="methodId">等待输入...</span></p>
            `;
            
            document.getElementById('callbackFunction').innerHTML = `
                <p>等待接收查询结果</p>
                <p id="callbackResult" class="mt-2 text-sm text-gray-500">结果将显示在这里</p>
            `;
        }

        // 开始演示
        document.getElementById('startDemo').addEventListener('click', () => {
            resetDemo();
            
            const studentId = document.getElementById('studentId').value;
            document.getElementById('displayId').textContent = studentId;
            document.getElementById('methodId').textContent = studentId;
            
            // 更新步骤1为活动状态
            updateStep(1, 'active');
            
            // 更新主程序显示
            document.getElementById('mainProgram').innerHTML = `
                <p>正在调用 GetStudentByID</p>
                <p class="mt-2 text-sm">参数: ID = ${studentId}</p>
                <p class="text-sm">回调函数已传入</p>
            `;
            
            log('主程序开始执行');
            log(`准备获取ID为 ${studentId} 的学生信息`);
            
            // 1秒后开始调用方法，让用户有时间看清
            setTimeout(() => {
                // 定义回调函数
                const callback = function(result) {
                    log('回调函数被调用，开始处理结果');
                    
                    // 更新回调函数显示
                    if (result.length > 0) {
                        document.getElementById('callbackFunction').innerHTML = `
                            <p>收到查询结果并处理</p>
                            <p class="mt-2 text-sm">ID: ${result[0].ID}</p>
                            <p class="text-sm">姓名: ${result[0].姓名}</p>
                            <p class="text-sm">班级: ${result[0].班级}</p>
                            <p class="text-sm">年龄: ${result[0].年龄}</p>
                        `;
                        log(`处理结果: 姓名=${result[0].姓名}, 班级=${result[0].班级}, 年龄=${result[0].年龄}`);
                    } else {
                        document.getElementById('callbackFunction').innerHTML = `
                            <p>收到查询结果并处理</p>
                            <p class="mt-2 text-sm text-red-500">未找到该学生信息</p>
                        `;
                        log('处理结果: 未找到该学生信息');
                    }
                    
                    log('回调函数执行完成');
                    updateStep(3, 'completed');
                };
                
                // 调用GetStudentByID方法，并传入回调函数
                GetStudentByID(studentId, callback);
                
                // 更新步骤1为已完成
                setTimeout(() => {
                    updateStep(1, 'completed');
                }, 500);
            }, 1000);
        });

        // 重置按钮事件
        document.getElementById('resetDemo').addEventListener('click', resetDemo);
        
        // 输入ID变化时更新显示
        document.getElementById('studentId').addEventListener('input', (e) => {
            document.getElementById('displayId').textContent = e.target.value;
        });
    </script>
</body>
</html>
